﻿/*Copyright (c) 2012 Cesar Ramirez
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial 
 * portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/

using System;
using System.Collections.Generic;
using System.ComponentModel; 
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using MechTactics.GameElements;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System.Net;
using System.IO;

namespace MechTactics
{
    public partial class Launcher : Form
    {
        public delegate void updateTxtDisplayCallback(String txt);
        private updateTxtDisplayCallback updateText;

        public delegate void updateButtonStateCallback(bool running);
        private updateButtonStateCallback updateButton;

        public delegate void updateScoreCallback(int id, int ore, int units, int score);
        private updateScoreCallback updateScore;

        private Thread serverThread;
        private Thread displayThread;
        private Server server;
        private Display display;
        private MapGenerator mapper;

        public Launcher()
        {
            InitializeComponent();
            updateText = new updateTxtDisplayCallback(this.logMessage);
            updateButton = new updateButtonStateCallback(this.buttonState);
            updateScore = new updateScoreCallback(this.newScore);
            initializeDisplay();
            labelIp.Text = LocalIPAddress();
        }

        private void tabPage1_Click(object sender, EventArgs e)
        {

        }

        private void buttonGenerate_Click(object sender, EventArgs e)
        {
            server = new Server(2);
            logMessage("Starting Map Generator");
            mapper = new MapGenerator(2, ((int)numericUpDownDensity.Value * 2) + 3, ((int)numericUpDownSize.Value * 2) + 1, 10, ((int)numericUpDownMod.Value / 2));
            logMessage("Creating Map");
            mapper.CreateMap();
            server.setMap(mapper.getMap(), mapper.max_height, mapper.getInitialPositions());
            display.setSimulator(server.sim);
            buttonGo.Enabled = true;
        }


        private void buttonGo_Click(object sender, EventArgs e)
        {
            serverThread = new Thread(new ThreadStart(initializeServer));
            serverThread.Start();
            //displayThread = new Thread(new ThreadStart(initializeDisplay));
            //displayThread.Start();
            buttonGenerate.Enabled = false;
            buttonStop.Enabled = true;
            buttonGo.Enabled = false;
        }

        private void initializeServer()
        {
            startServer();
        }

        private void initializeServerSavedGame()
        {
            startServerSavedGame();
        }

        private void startServer()
        {
            logMessage("Starting server");
            server.logMessage(updateText);
            server.serverRunning(buttonState);
            server.newScore(updateScore);
            logMessage("Listening for clients");
            if (server.startListening())
            {
                logMessage("All clients connected, starting game");
                server.startGame();
            }
            else
            {
                logMessage("Game stopped");
            }
        }

        private void startServerSavedGame()
        {
            logMessage("Starting server");
            server.logMessage(updateText);
            server.startLoadingData(txtFileChosen.Text);
            server.newScore(updateScore);
            server.serverRunning(buttonState);
            display.setSimulator(server.sim);
            server.startGame();
            logMessage("Game stopped");
        }
        
        private void initializeDisplay()
        {
            display = new Display(glControl1);
        }

        private void btnFileChooser_Click(object sender, EventArgs e)
        {
            fileChooseDialog.Filter = "Game XML Files|*.msg|All Files (*.*)|*.*";
            fileChooseDialog.InitialDirectory = Application.ExecutablePath;
            if (fileChooseDialog.ShowDialog() == DialogResult.OK)
            {
                txtFileChosen.Text = fileChooseDialog.FileName;
            }
            btnVisualize.Enabled = true;
        }

        private void btnVisualize_Click(object sender, EventArgs e)
        {
            server = new Server(2);
            serverThread = new Thread(new ThreadStart(initializeServerSavedGame));
            serverThread.Start();
            buttonGenerate.Enabled = false;
            buttonStop.Enabled = true;
            buttonGo.Enabled = false;
        }

        private void buttonState(bool running)
        {
            try
            {
                if (running)
                {
                    buttonStop.Invoke(new MethodInvoker(delegate { buttonStop.Enabled = true; }));
                    buttonGo.Invoke(new MethodInvoker(delegate { buttonGo.Enabled = false; }));
                    buttonGenerate.Invoke(new MethodInvoker(delegate { buttonGenerate.Enabled = false; }));
                }
                else
                {
                    buttonStop.Invoke(new MethodInvoker(delegate { buttonStop.Enabled = false; }));
                    buttonGo.Invoke(new MethodInvoker(delegate { buttonGo.Enabled = true; }));
                    buttonGenerate.Invoke(new MethodInvoker(delegate { buttonGenerate.Enabled = true; }));
                }
            }
            catch (Exception e)
            { }
        }

        private void logMessage(string message)
        {
            try
            {
                textBoxOutput.Invoke(new MethodInvoker(delegate { textBoxOutput.AppendText(message + "\n"); }));
            }catch(Exception e)
            {}
        }

        private void newScore(int id, int ore, int units, int score)
        {
            try
            {
                switch (id)
                {
                    case 0:
                        labelP1Ore.Invoke(new MethodInvoker(delegate { labelP1Ore.Text = "Ore: " + ore.ToString(); }));
                        labelP1Units.Invoke(new MethodInvoker(delegate { labelP1Units.Text = "Possessions: " + units.ToString(); }));
                        labelP1Score.Invoke(new MethodInvoker(delegate { labelP1Score.Text = "Score: " + score.ToString(); }));
                        break;
                    case 1:
                        labelP2Ore.Invoke(new MethodInvoker(delegate { labelP2Ore.Text = "Ore: " + ore.ToString(); }));
                        labelP2Units.Invoke(new MethodInvoker(delegate { labelP2Units.Text = "Possessions: " + units.ToString(); }));
                        labelP2Score.Invoke(new MethodInvoker(delegate { labelP2Score.Text = "Score: " + score.ToString(); }));
                        break;
                }
            }
            catch(Exception e)
            { }
        }

        private void glControl1_Load_1(object sender, EventArgs e)
        {
            display.load(sender, e);
            Application.Idle += display.Application_Idle;
        }

        private void glControl1_Paint_1(object sender, PaintEventArgs e)
        {
            display.paint(sender, e);
        }

        private void glControl1_KeyDown(object sender, KeyEventArgs e)
        {
           
        }

        private void glControl1_Resize(object sender, EventArgs e)
        {
            display.resize(sender, e);
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            server.stopServer();
            buttonStop.Enabled = false;
            buttonGo.Enabled = true;
            buttonGenerate.Enabled = true;
        }

        private string LocalIPAddress()
        {
            IPHostEntry host;
            string localIP = "";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily.ToString() == "InterNetwork")
                {
                    localIP += ip.ToString() + " - ";
                }
            }
            return localIP.Substring(0, localIP.Length - 3);
        }
    }
}
